﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CashCommon;
using System.Windows.Forms;
using CashResource;
using System.ComponentModel;
using System.Data;

namespace Cash.Model
{
    public interface ICashRegisterGate
    {
        #region Методы класса

        /// <summary>
        /// Удаление кассового счета
        /// </summary>
        /// <param name="activeUserId">Пользователь, выполняющий операцию</param>
        /// <param name="cashAccountId">Идентификатор счета</param>
        void RemoveById(int[] cashRegisterIds);
        void PrintCheck(CashRegister cashRegister);
        PostResult PostDocuments(DateTime dateTime, int fDivision);

        #endregion

        #region Работа с базой данных

        /// <summary>
        /// Данные из экземпляра класса реестра чеков, сохраняются в базе
        /// </summary>
        /// <param name="cashRegister">Чек, к которому применяются изменения</param>
        void ApplyToDb(CashRegister cashRegister);

        /// <summary>
        /// Данные в экземпляре класса чека обновляются из базы данных
        /// </summary>
        /// <param name="cashRegister">Экземпляр чека</param>
        void RefreshFromDb(CashRegister cashRegister);

        Sequence GetSequence(SqlSwitch swth);

        #endregion
    }

    public class CashRegister
    {
        #region Создание чека

        /// <summary>
        /// Статический метод класса для создания нового чека в системе
        /// </summary>
        public static CashRegister Instant()
        {
            return new CashRegister();
        }
        /// <summary>
        /// По переданному идентификатору, создается экземпляр класса чека.
        /// </summary>
        /// <param name="userId">Идентификатор чека в базе данных</param>
        /// <returns>Возвращается экземпляр класса чека. Если чек с заданным ID  не найден, возвращается null</returns>
        public static CashRegister Instant(int id)
        {
            return new CashRegister(id);
        }
        /// <summary>
        /// Защищенный конструктор для создания "пустого" чека
        /// </summary>
        protected CashRegister() { }
        /// <summary>
        /// Защищенный конструктор для создания чека, и инициалзизации его полей из базы данных
        /// </summary>
        protected CashRegister(int id) 
        {
            this.ID = id;
            RefreshFromDb();
        }

        #endregion

        #region Методы класса

        public static Sequence OpenSequence(ref DataGridView dataGrid, SqlSwitch sqlSwitch, List<string> fieldsVisible)
        {
            try
            {
                Sequence sqc = Builder.CashRegisterGate.GetSequence(null);
                if (sqlSwitch != null)
                    sqc.SqlSwitch = sqlSwitch;
                sqc.PrimaryKey.Add("LINK");
                sqc.DGV = dataGrid;
                sqc.Open();

                if (fieldsVisible != null)
                    sqc.SetVisibleFields(fieldsVisible);
                return sqc;
            }
            catch(Exception err)
            {
                throw new ECashSql(MessageType.AllertLog, SqlErrors.ErrorOpenSqlRegister, err);
            }
        }
        public static int RemoveById(int[] cashRegisterIds)
        {
            _backgroundWorker = new BackgroundWorker();
            _cashRegisterIds = cashRegisterIds;
            _backgroundWorker.DoWork += new DoWorkEventHandler(bgw_DoWorkForDelete);
            _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompletedForDelete);
            _backgroundWorker.RunWorkerAsync();
            return _frmProgress.ShowDialog() == DialogResult.OK? 0 : 1;
        }
        public static PostResult PostDocuments(DateTime dateTime, int fDivision)
        {
            return _gate.PostDocuments(dateTime, fDivision);
        }
        public void PrintCheck()
        {
            _backgroundWorker = new BackgroundWorker();
            _backgroundWorker.DoWork += new DoWorkEventHandler(bgwPrintCheck);
            _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwCompletedPrintCheck);
            _backgroundWorker.RunWorkerAsync();
            _frmProgress.FormCaption = CommonText.ProgressFormTitlePrint;
            _frmProgress.ShowDialog();
        }
        public void InitFromAccount(CashAccount cashAccount)
        {
            this.CashAccount = cashAccount;
            this.AbonentCode = cashAccount.Number;
            this.AbonentName = cashAccount.AbonentName;
            this.Amount = cashAccount.Amount;
            this.C_Foundation = cashAccount.C_Foundation;
            this.DatePrint = cashAccount.DatePrint;
            this.F_Division = cashAccount.F_Division;
            this.F_Sale_Categories = cashAccount.F_Sale_Categories;
            this.F_Sale_Items = cashAccount.F_Sale_Items;
            this.F_Subscr = cashAccount.F_Subscr;
            this.N_Releaze = cashAccount.N_Releaze;
            this.N_Tax = cashAccount.N_Tax;
            this.Number = 0;
            this.OrderNumber = cashAccount.C_Order_Number;
            this.Sale_Categories_Name = cashAccount.Sale_Categories_Name;
            this.Sale_Items_Name = cashAccount.Sale_Items_Name;
        }
        
        #endregion

        #region Свойства

        /// <summary>
        /// Идентификатор чека в БД
        /// </summary>
        public int ID { get; set; } 
        /// <summary>
        /// True-чек распечатан на ККМ, False - не распечатан
        /// </summary>
        public bool IsPrinted { get; set; }
        /// <summary>
        /// Дата печати чека
        /// </summary>
        public DateTime DatePrint { get; set; }
        /// <summary>
        /// Наименование документа (обычно 'Копия чека')
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Кассовый номер
        /// </summary>
        public int Number { get; set; }
        /// <summary>
        /// Сумма итого
        /// </summary>
        public double Amount { get; set; }
        /// <summary>
        /// Код абонента
        /// </summary>
        public string AbonentCode { get; set; }
        /// <summary>
        /// Наименование абонента
        /// </summary>
        public string AbonentName { get; set; }
        /// <summary>
        /// Идентификатор абонента
        /// </summary>
        public int F_Subscr { get; set; }
        /// <summary>
        /// НДС
        /// </summary>
        public double N_Tax { get; set; }
        /// <summary>
        /// Основание для выдачи чека
        /// </summary>
        public string C_Foundation { get; set; }
        /// <summary>
        /// Номер договора
        /// </summary>
        public string OrderNumber { get; set; }
        /// <summary>
        /// Вид энергии
        /// </summary>
        public string Sale_Categories_Name { get; set; }
        /// <summary>
        /// Идентификатор вида энергии
        /// </summary>
        public int F_Sale_Categories { get; set; }
        /// <summary>
        /// Статья реализации
        /// </summary>
        public string Sale_Items_Name { get; set; }
        /// <summary>
        /// Статья реалзиации
        /// </summary>
        public int F_Sale_Items { get; set; }
        /// <summary>
        /// Если чек является чеком реализации = 1, если нет 0
        /// </summary>
        public int N_Releaze { get; set; }
        /// <summary>
        /// Текущий пользователь системы
        /// </summary>
        public CashEmployer CashEmployer { get { return CashEmployer.Inst; } }
        /// <summary>
        /// Пользователь создавший запись в системе
        /// </summary>
        public string CreatedEmployer { get; set; }
        /// <summary>
        /// Идентификатор подразделения
        /// </summary>
        public int F_Division { get; set; }
        /// <summary>
        /// Счет на основе которого создан чек
        /// </summary>
        public CashAccount CashAccount { get; set; }
        /// <summary>
        /// Офицальное наименование отделения
        /// </summary>
        #endregion

        #region Helper
        
        private void bgwPrintCheck(object sender, DoWorkEventArgs e)
        {
            _gate.PrintCheck(this);
            _cashRegister = this;
        }
        private void bgwCompletedPrintCheck(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                _cashRegister.IsPrinted = false;
                if (_frmProgress != null)
                    _frmProgress.DialogResult = DialogResult.Cancel;
                throw new ECashSql(MessageType.AllertLog, CommonError.CashRegisterPrintError, e.Error.ToString());
            }
            else
            {
                _cashRegister.IsPrinted = true;
                if (_frmProgress != null)
                    _frmProgress.DialogResult = DialogResult.OK;
            }
        }
        private static void bgw_DoWorkForDelete(object sender, DoWorkEventArgs e)
        {
            _gate.RemoveById(_cashRegisterIds);
        }
        private static void bgw_RunWorkerCompletedForDelete(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (_frmProgress != null)
                    _frmProgress.DialogResult = DialogResult.Cancel;
                throw new ECashSql(MessageType.AllertLog, SqlErrors.ErrorDeleteSqlRegister, e.Error.ToString());
            }
                if (_frmProgress != null)
                    _frmProgress.DialogResult = DialogResult.OK;
        }

        /// <summary>
        /// Значения полей чека обновляются значениями из базы данных
        /// </summary>
        public void RefreshFromDb()
        {
            try
            {
                _gate.RefreshFromDb(this);
            }
            catch (Exception err)
            {
                throw new ECashSql(MessageType.AllertLog, SqlErrors.ErrorRefreshSqlRegister, err);
            }
        }
        /// <summary>
        /// Новые значения полей чека сохраняются в базе данных
        /// </summary>
        public void ApplyToDb()
        {
            try
            {
                _gate.ApplyToDb(this);
            }
            catch (Exception err) 
            {
                throw new ECashSql(MessageType.AllertLog, SqlErrors.ErrorApplySqlRegister, err);
            }
        }

        #endregion

        #region Fields

        private static ICashRegisterGate _gate = Builder.CashRegisterGate;
        private static FrmProgress _frmProgress = new FrmProgress(CommonText.ProgressFormTitleSQL);
        private static BackgroundWorker _backgroundWorker = new BackgroundWorker();
        private static int[] _cashRegisterIds;
        private static CashRegister _cashRegister;

        #endregion

    }
}
